﻿using IRepositories.Base;
using Microsoft.EntityFrameworkCore;
using System.Linq.Expressions;
using System.Linq.Dynamic.Core;
using MyEntityFramework;

namespace Repositories.Base
{
    /// <summary>
    /// 仓储接口实现
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    public class BaseRepository<TEntity> : IBaseRepository<TEntity> where TEntity : class, new()
    {
        private readonly MyDbContext _myDb;

        public BaseRepository(MyDbContext myDb)
        {
            _myDb = myDb;
        }
        //public BaseRepository()
        //{
        //    _myDb = new MyDbContext();
        //}
        /// <summary>
        /// 暴露 DbContext 提供给自定义仓储进行使用
        /// </summary>
        /// <returns></returns>
        protected MyDbContext DbContext()
        {
            return _myDb;
        }
        /// <summary>
        /// 添加实体
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="autoSave"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<TEntity> InsertAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            var saveEntity = (await _myDb.Set<TEntity>().AddAsync(entity, cancellationToken)).Entity;
            if (autoSave)
            {
                await _myDb.SaveChangesAsync(cancellationToken);
            }
            return saveEntity;
        }

        public async Task InsertManyAsync(IEnumerable<TEntity> entities, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            var entityArray = entities.ToArray();
            await _myDb.Set<TEntity>().AddRangeAsync(entityArray, cancellationToken);
            if (autoSave)
            {
                await _myDb.SaveChangesAsync(cancellationToken);
            }
        }

        public async Task<TEntity> UpdateAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            _myDb.Attach(entity);
            var updateEntity = _myDb.Update(entity).Entity;
            if (autoSave)
            {
                await _myDb.SaveChangesAsync(cancellationToken);
            }
            return updateEntity;
        }

        public async Task UpdateManyAsync(IEnumerable<TEntity> entities, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            _myDb.Set<TEntity>().AttachRange(entities);
            if (autoSave)
            {
                await _myDb.SaveChangesAsync(cancellationToken);
            }
        }

        public async Task DeleteAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            _myDb.Set<TEntity>().Remove(entity);
            if (autoSave) await _myDb.SaveChangesAsync(cancellationToken);
        }

        public async Task DeleteAsync(Expression<Func<TEntity, bool>> predicate, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            var dbSet = _myDb.Set<TEntity>();
            var entities = await dbSet.Where(predicate).ToListAsync(cancellationToken);
            await DeleteManyAsync(entities, autoSave, cancellationToken);
            if (autoSave) await _myDb.SaveChangesAsync(cancellationToken);
        }

        public async Task DeleteManyAsync(IEnumerable<TEntity> entities, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            _myDb.RemoveRange(entities);
            if (autoSave) await _myDb.SaveChangesAsync(cancellationToken);
        }

        public Task<TEntity> FindAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default)
        {
            return _myDb.Set<TEntity>().Where(predicate).SingleOrDefaultAsync(cancellationToken);
        }

        public async Task<TEntity> GetAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default)
        {
            var entity = await FindAsync(predicate, cancellationToken);
            if(entity==null) throw new Exception(nameof(TEntity)+"数据不存在");
            return entity;
        }

        public Task<List<TEntity>> GetListAsync(CancellationToken cancellationToken = default)
        {
            return _myDb.Set<TEntity>().ToListAsync(cancellationToken);
        }

        public Task<List<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default)
        {
            return _myDb.Set<TEntity>().Where(predicate).ToListAsync(cancellationToken);
        }

        public Task<List<TEntity>> GetPagedListAsync(int skipCount, int maxResultCount, string sorting, CancellationToken cancellationToken = default)
        {
            return _myDb.Set<TEntity>().OrderBy(sorting).Skip(skipCount).Take(maxResultCount).ToListAsync(cancellationToken);
        }

        public Task<long> GetCountAsync(CancellationToken cancellationToken = default)
        {
            return _myDb.Set<TEntity>().LongCountAsync(cancellationToken);
        }

        public Task<long> GetCountAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken)
        {
            return _myDb.Set<TEntity>().Where(predicate).LongCountAsync(cancellationToken);
        }
    }
}
